/****************************************************************************** * Copyright (C) Ultraleap, Inc. 2011-2021. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * * between Ultraleap and you, your company or other organization. * ******************************************************************************/ using Leap.Unity.Interaction; using UnityEngine; namespace UHI.Tracking.InteractionEngine.Examples { /// /// The spaceship in this example is a kinematic rigidbody with a force API, but having /// a rigidbody on your Interaction Manager's reference frame is entirely optional. Any /// moving transform can provide a frame of reference for the Interaction Manager and /// encompassing interfaces. /// /// This script provides a "velocity" and "angular velocity" abstraction for the /// AutopilotSystem in the example, and moves the ship's transform appropriately. /// /// The important thing when using a moving reference frame is that you move the /// Interaction Manager's transform before its FixedUpdate runs. This script uses /// the manager's OnPrePhysicalUpdate to ensure this, which it calls at the beginning /// of its FixedUpdate. /// [AddComponentMenu("")] public class Spaceship : MonoBehaviour { private Rigidbody _body; /// /// The ship contains Colliders, so it is given a kinematic Rigidbody to prevent /// the overhead of moving Colliders every frame. /// /// Setting the rigidbody's position is not important for the Interaction Manager; /// only the transform's positional movement establishes a moving reference frame! /// public #if UNITY_EDITOR new #endif Rigidbody rigidbody { get { return _body; } } private float _mass = 10F; private Vector3 _velocity; public Vector3 velocity { get { return _velocity; } set { _velocity = value; } } public Vector3 shipAlignedVelocity { get { return Quaternion.Inverse(this.transform.rotation) * _velocity; } } private Vector3 _angularVelocity; public Vector3 angularVelocity { get { return _angularVelocity; } set { _angularVelocity = value; } } public Vector3 shipAlignedAngularVelocity { get { return Quaternion.Inverse(this.transform.rotation) * _angularVelocity; } } private Vector3 _accumulatedForce; private Vector3 _accumulatedTorque; void Awake() { _body = GetComponent(); _body.mass = _mass; _body.isKinematic = true; } void Start() { // The ship is moved in the manager's OnPrePhysicalUpdate callback, which ensures // (1) the ship's transform is updated before the Interaction Manager runs, and // (2) the ship's transform is updated in FixedUpdate. // // The Interaction Manager takes into account how it has moved since its last // update, and informs interaction controllers appropriately, allowing // interfaces to function properly. InteractionManager.instance.OnPrePhysicalUpdate += updateShipPhysics; } private void updateShipPhysics() { // Update velocity. Vector3 acceleration = _accumulatedForce / _mass; _velocity += acceleration * Time.deltaTime; _accumulatedForce = Vector3.zero; // Update position. Vector3 newPosition = this.transform.position + _velocity * Time.deltaTime; this.transform.position = newPosition; // Update angular velocity. Vector3 eulerAcceleration = _accumulatedTorque; _angularVelocity += eulerAcceleration * Time.deltaTime; _accumulatedTorque = Vector3.zero; // Update rotation. Quaternion newRotation = Quaternion.Euler(_angularVelocity * Time.deltaTime) * this.transform.rotation; this.transform.rotation = newRotation; // Sync transforms with the Physics engine so Rigidbody changes reflect // the movement of the ship. (Required for 2017.3 and newer.) #if UNITY_2017_3_OR_NEWER Physics.SyncTransforms(); #endif } #region Ship Forces API public void AddForce(Vector3 force) { _accumulatedForce += force; } public void AddForceAtPosition(Vector3 force, Vector3 position) { Vector3 toCenterOfMass = this.transform.TransformPoint(_body.centerOfMass) - position; float forceCMAngle = Vector3.Angle(force, toCenterOfMass); // Linear force Vector3 linForce = force * Mathf.Cos(forceCMAngle); _accumulatedForce += linForce; // Torque Vector3 torqueVector = force * Mathf.Sin(forceCMAngle) * toCenterOfMass.magnitude; _accumulatedTorque += Vector3.Cross(torqueVector, toCenterOfMass); } public void AddShipAlignedTorque(Vector3 shipAlignedTorque) { _accumulatedTorque += this.transform.rotation * shipAlignedTorque; } public void AddShipAlignedForce(Vector3 shipAlignedForce) { _accumulatedForce += this.transform.rotation * shipAlignedForce; } #endregion } }